﻿using System;
using System.Data;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.Web.Caching;
using System.Configuration;
using System.IO;
using System.Xml;
using System.Xml.Schema;

using Geoconcepts.Common;

namespace Geoconcepts.Queries
{
    /// <summary>
    /// Descripción breve de GeoconceptsQueries
    /// </summary>
    [WebService(Namespace = "http://www.geoconcepts.es/cinespace/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ToolboxItem(false)]
    
    
    
    public class GeoconceptsQueries : System.Web.Services.WebService
    {
        private Cache mObjCache;
        private SpatialQueries moSpatialQueries;
        private string strPerformanceLogFile;
        private SemanticQueries oSemanticQueries;
        //private SemanticQueries moSemanticQueries;

        public GeoconceptsQueries()
        {
            Initialize();
        }

        /// <summary>
        /// Retrieves the geoconcepts that contain a location and the related ones.
        /// </summary>
        /// <param name="longitude">In grades with decimal fractions</param>
        /// <param name="latitude">In grades with decimal fractions</param>
        /// <param name="strFormat">xml format of results</param>
        /// <returns>Set of geogoncepts in XML format</returns>
        [WebMethod(Description = "Retrieves a list of Geoconcepts that contain a location and the related ones. The results are given in XML. \nParameters: longitude: In grades with decimal fractions (ie. -1.9855444) latitude:In grades with decimal fractions. (ie. 43.319141)")]
        public XmlElement WhereAmI(double longitude, double latitude, string strFormat)
        {
            try
            {
                XmlDocument xmlDocument = new XmlDocument();
                xmlDocument.PreserveWhitespace = true;

                string sFullURL = "";
                string strWebOrFile = "web";
                //string sGeoConceptsIAmIn = "";
                //string sWhereAmI = "";
                string sCity;
                string strIP = "";

                #region Trace user
                // Get IP from user
                try
                {
                    
                    strIP = Context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
                    if (strIP == null || strIP == string.Empty)
                    {
                        strIP = Context.Request.ServerVariables["REMOTE_ADDR"];
                    }
                }
                catch (Exception ex)
                {
                }
                #endregion Trace user

                DateTime dtimeIni = DateTime.Now;

                if (strFormat.Equals("kml", StringComparison.OrdinalIgnoreCase))
                {
                    xmlDocument = moSpatialQueries.SpatialWhereAmI_KML(longitude, latitude, out sCity);
                }
                else
                {
                    AnnotationRecommendations dtsAnnotation = new AnnotationRecommendations();
                    dtsAnnotation = moSpatialQueries.SpatialWhereAmI_Annotations(longitude, latitude, out sCity);

                    TimeSpan tspanExecution = DateTime.Now - dtimeIni;

                    Ficheros.GrabarLog(strPerformanceLogFile, "GeoconceptsQueries.WhereAmI", "SpatialQueries.SpatialWhereAmI",
                        longitude.ToString() + "," + latitude.ToString() + "," + sCity, tspanExecution.TotalMilliseconds, "performance," + strIP);

                    /*
                
                    #region Create Dataset
                    AnnotationRecommendations.OrientationRow drOrientationRow = dtsAnnotation.Orientation.NewOrientationRow();
                    drOrientationRow.lon = longitude;
                    drOrientationRow.lat = latitude;
                    drOrientationRow.bearing = 0;
                    dtsAnnotation.Orientation.AddOrientationRow(drOrientationRow);
                    dtsAnnotation.AcceptChanges();
                    for (int i = 0; i < strGeoconceptsArray.Length; i++)
                    {
                        AnnotationRecommendations.GeoconceptsRow drGeoconceptsRow = dtsAnnotation.Geoconcepts.NewGeoconceptsRow();
                        drGeoconceptsRow.SetParentRow(drOrientationRow);
                        drGeoconceptsRow.geoconcept = strGeoconceptsArray[i];
                        drGeoconceptsRow.relevance = 0;
                        drGeoconceptsRow.centroidLat = 0;
                        drGeoconceptsRow.centroidLon = 0;
                        dtsAnnotation.Geoconcepts.AddGeoconceptsRow(drGeoconceptsRow);
                        dtsAnnotation.AcceptChanges();
                    }
                    #endregion Create Dataset
                    */
                    /*
                    #region Semantic Query
                    dtimeIni = DateTime.Now;

                    if (sGeoConceptsIAmIn.Contains(","))
                        sWhereAmI = oSemanticQueries.RetrieveGConceptSetGeoGraph(sCity, sGeoConceptsIAmIn);
                    else
                        sWhereAmI = oSemanticQueries.RetrieveGConceptGeoGraph(sCity, sGeoConceptsIAmIn);

                    tspanExecution = DateTime.Now - dtimeIni;
                    Ficheros.GrabarLog(strPerformanceLogFile, "GeoconceptsQueries.WhereAmI", "SemanticQueries.RetrieveGConceptSetGeoGraph",
                        sGeoConceptsIAmIn + "," + sCity + ",Resultado: " + sWhereAmI, tspanExecution.TotalMilliseconds, "performance," + strIP);
                    #endregion Semantic Query
                    */


                    xmlDocument.LoadXml(dtsAnnotation.GetXml());
                }
                return xmlDocument.DocumentElement;
            }
            catch (Exception exc)
            {
                throw (exc);
            }
        }

        /// <summary>
        /// Trivial example to test web service connection
        /// </summary>
        /// <param name="strName"></param>
        /// <returns></returns>
        [WebMethod(Description = "Trivial example to test web service connection")]
        public string WhatIsYourName(string strName)
        {
            string strResult = "";
            return strName + " " + strResult + " Current Windows Identity: " + System.Security.Principal.WindowsIdentity.GetCurrent().Name;
        }

        /// <summary>
        /// Returns the XML Schema of the Dataset AnnotationRecommendations
        /// </summary>
        /// <returns></returns>
        [WebMethod(Description = "Returns the XML Schema of the Dataset AnnotationRecommendations. If string 'true' is passed, it gets the Microsoft DataSet Typed xsd")]
        public XmlElement GetAnnotationRecommendationsSchema(string strMicrosoft)
        {
            AnnotationRecommendations dtsAnnotation = new AnnotationRecommendations();
            XmlDocument xmlDocument = new XmlDocument();
            try
            {
                if (strMicrosoft == "true")
                {
                    xmlDocument.PreserveWhitespace = true;
                    xmlDocument.LoadXml(dtsAnnotation.GetXmlSchema());
                }
                else
                {

                    xmlDocument.PreserveWhitespace = true;
                    string strXmlFile = AppDomain.CurrentDomain.BaseDirectory + "\\bin\\AnnotationRecommendations.xsd";
                    xmlDocument.Load(strXmlFile);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return xmlDocument.DocumentElement;
        }



        /// <summary>
        /// Given a segment representing the user location and direction of view, it retrieves the set of GeoConcepts in sight and related ones
        /// and also geoconcepts in other posible directions from the same point.
        /// </summary>
        /// <param name="longitude">In grades with decimal fractions</param>
        /// <param name="latitude">In grades with decimal fractions</param>
        /// <param name="bearing">In geographic format (N=0º), in radians</param>
        /// <param name="distance">In meters</param>
        /// <param name="viewAngle">In grades</param>
        /// <param name="bearingShots">Number of directions that are retrieved</param>
        /// <param name="strFormat">xml format of results</param>
        /// <returns>Set of geogoncepts in string format</returns>
        [WebMethod(Description = "Given a segment representing the user location and direction of view, it retrieves the set of GeoConcepts in sight" + 
            " and also geoconcepts in other 'bearingShots' posible directions from the same point. The results are given in XML format " + 
            "\nParameters: longitude: In grades with decimal fractions (ie. -1.9855444) latitude:In grades with decimal fractions. (ie. 43.319141)" +
            " bearing: In geographic format (N=0º), In radians (ie. 0.3) distance: In meters (ie. 500) viewAngle: In radians (ie 0.15) bearingShots: integer in [2,36]")]
        public XmlElement WhatAmILookingAtAroundMe(double longitude, double latitude, double bearing, double distance, int bearingShots,string strFormat)
        {

           
            
            try
            {
                XmlDocument xmlDocument = new XmlDocument();
                xmlDocument.PreserveWhitespace = true;
                string sCity;
                double dViewAngle = Convert.ToDouble(ConfigurationManager.AppSettings["viewAngle"]);

                if (bearingShots < 2 || bearingShots > 36)
                {
                    bearingShots = 2;
                }
                // The results should be returned in AnnotationRecommendations dataset.
                // 12 direcciones: 0,5236
                double bearingStep = 2 * Math.PI / bearingShots;

                if (strFormat.Equals("kml", StringComparison.OrdinalIgnoreCase))
                {
                    xmlDocument = moSpatialQueries.SpatialWhatAmILookingAroundMe_Kml(longitude, latitude, bearing, distance, dViewAngle, bearingShots, out sCity);
                }
                else
                {
                    AnnotationRecommendations dtsAnnotationRecommendations = new AnnotationRecommendations();
                    for (int i = 0; i < bearingShots; i++)
                    {
                        dtsAnnotationRecommendations.Merge(WhatGeoconceptstAmILookingAt(longitude, latitude, bearing, distance, dViewAngle));
                        bearing = bearingStep + bearing;
                        if (bearing > 2 * Math.PI)
                        {
                            bearing = bearing - 2 * Math.PI;
                        }
                    }
                    xmlDocument.LoadXml(dtsAnnotationRecommendations.GetXml());
                }
                return xmlDocument.DocumentElement;
            }
            catch (Exception ex)
            {
                throw (ex);
            }
        }


        /// <summary>
        /// Given a segment representing the user location and direction of view, it retrieves the set of GeoConcepts in sight and the related ones.
        /// </summary>
        /// <param name="longitude">In grades with decimal fractions</param>
        /// <param name="latitude">In grades with decimal fractions</param>
        /// <param name="bearing">In geographic format (N=0º), in radians</param>
        /// <param name="distance">In meters</param>
        /// <param name="strFormat">xml format of results</param>
        /// <returns>Set of geogoncepts in string format</returns>
        [WebMethod(Description = "Given a segment representing the user location and direction of view, it retrieves the set of GeoConcepts in sight and the related ones. The results are given in XML format. \nParameters: longitude: In grades with decimal fractions (ie. -1.9855444) latitude:In grades with decimal fractions. (ie. 43.319141) bearing: In geographic format (N=0º), In radians (ie. 0.3) distance: In meters (ie. 500)")]
        public XmlElement WhatAmILookingAt(double longitude, double latitude, double bearing, double distance, string strFormat)
        {

           
            try
            {
                string sCity;
                double dViewAngle = Convert.ToDouble(ConfigurationManager.AppSettings["viewAngle"]);
                XmlDocument xmlDocument = new XmlDocument();
                xmlDocument.PreserveWhitespace = true;

                if (strFormat.Equals("kml", StringComparison.OrdinalIgnoreCase))
                {
                    xmlDocument = moSpatialQueries.SpatialWhatAmILookingAt_Kml(longitude, latitude, bearing, distance, dViewAngle, out sCity);
                }
                else
                {
                    AnnotationRecommendations dtsAnnotation = new AnnotationRecommendations();
                    dtsAnnotation = WhatGeoconceptstAmILookingAt(longitude, latitude, bearing, distance, dViewAngle);
                    xmlDocument.LoadXml(dtsAnnotation.GetXml());
                    
                }
                return xmlDocument.DocumentElement;
            }
            catch (Exception ex)
            {
                throw (ex);
            }
        }

        /// <summary>
        /// Given a segment representing the user location and direction of view, it retrieves the set of GeoConcepts in sight and the related ones.
        /// </summary>
        /// <param name="longitude">In grades with decimal fractions</param>
        /// <param name="latitude">In grades with decimal fractions</param>
        /// <param name="bearing">In geographic format (N=0º), in radians</param>
        /// <param name="distance">In meters</param>
        /// <param name="viewAngle">In grades</param>
        /// <returns>Set of geogoncepts in AnnotationRecommendations format</returns>
        private AnnotationRecommendations WhatGeoconceptstAmILookingAt(double longitude, double latitude, double bearing, double distance, double viewAngle)
        {
            try
            {
                #region variables
                string sFullURL = "";
                string sGeoConceptsIAmLookingAt = "";
                string strWebOrFile = "web";
                //string sWhatAmILookingAt = "";
                string sCity;
                string strIP = "";
                AnnotationRecommendations dtsAnnotation = new AnnotationRecommendations();
                #endregion variables

                #region User Trace
                try
                {

                    strIP = Context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
                    if (strIP == null || strIP == string.Empty)
                    {
                        strIP = Context.Request.ServerVariables["REMOTE_ADDR"];
                    }
                }
                catch (Exception ex)
                {
                }
                #endregion User Trace

                #region Spatial Query
                DateTime dtimeIni = DateTime.Now;
                
                dtsAnnotation = moSpatialQueries.SpatialWhatAmILookingAt_Annotations(longitude, latitude, bearing, distance, viewAngle, out sCity);
                TimeSpan tspanExecution = DateTime.Now - dtimeIni;

                Ficheros.GrabarLog(strPerformanceLogFile, "GeoconceptsQueries.WhatGeoconceptsAmILookingAt", "SpatialQueries.SpatialWhatAmILookingAt",
                    longitude.ToString() + "," + latitude.ToString() + "," + bearing.ToString() + "," + distance.ToString() + "," + sCity, tspanExecution.TotalMilliseconds, "performance," + strIP);
                #endregion Spatial Query

                string[] strGeoconceptsArray = sGeoConceptsIAmLookingAt.Split(',');
/*
                #region Create Dataset
                AnnotationRecommendations.OrientationRow drOrientationRow = dtsAnnotation.Orientation.NewOrientationRow();
                drOrientationRow.lon = longitude;
                drOrientationRow.lat = latitude;
                drOrientationRow.bearing = bearing;
                dtsAnnotation.Orientation.AddOrientationRow(drOrientationRow);
                dtsAnnotation.AcceptChanges();
                for (int i = 0; i < strGeoconceptsArray.Length; i++)
                {
                    AnnotationRecommendations.GeoconceptsRow drGeoconceptsRow = dtsAnnotation.Geoconcepts.NewGeoconceptsRow();
                    drGeoconceptsRow.SetParentRow(drOrientationRow);
                    drGeoconceptsRow.geoconcept = strGeoconceptsArray[i];
                    drGeoconceptsRow.relevance = 0;
                    drGeoconceptsRow.centroidLat = 0;
                    drGeoconceptsRow.centroidLon = 0;
                    dtsAnnotation.Geoconcepts.AddGeoconceptsRow(drGeoconceptsRow);
                    dtsAnnotation.AcceptChanges();
                }
                #endregion CreateDataset
*/
                /*
                #region Semantic Query
                dtimeIni = DateTime.Now;
                
                if (sGeoConceptsIAmLookingAt.Contains(","))
                    sWhatAmILookingAt = oSemanticQueries.RetrieveGConceptSetGeoGraph(sCity, sGeoConceptsIAmLookingAt);
                else
                    sWhatAmILookingAt = oSemanticQueries.RetrieveGConceptGeoGraph(sCity, sGeoConceptsIAmLookingAt);

                tspanExecution = DateTime.Now - dtimeIni;
                Ficheros.GrabarLog(strPerformanceLogFile, "GeoconceptsQueries.WhatGeoconceptsAmILookingAt", "SemanticQueries.RetrieveGConceptSetGeoGraph",
                    sGeoConceptsIAmLookingAt + "," + sCity + ",Resultado: " + sWhatAmILookingAt , tspanExecution.TotalMilliseconds, "performance," + strIP);
                #endregion Semantic Query
                */
                return dtsAnnotation;
                 
            }
            catch (Exception exc)
            {
                throw (exc);
            }
        }



        private void Initialize()
        {
            try
            {
                HttpContext httpCurrent = HttpContext.Current;
                mObjCache = httpCurrent.Cache;

                moSpatialQueries = (SpatialQueries)mObjCache.Get("SpatialQueries");
                if (moSpatialQueries == null)
                {
                    //string sFile = ConfigurationManager.AppSettings["GeoConceptsFile"].ToString();

                    //if (!Network.ConnectionExists())
                    //{
                    //    sFile = ConfigurationManager.AppSettings["KmlFile"].ToString();
                    //}

                    //int iHuso = Convert.ToInt32(ConfigurationManager.AppSettings["Huso"]);

                    moSpatialQueries = new SpatialQueries();

                    System.TimeSpan tsDelay = new TimeSpan(0, 0, 30, 0, 0);
                    DateTime dtDelete = System.DateTime.Now + tsDelay;
                    mObjCache.Add("SpatialQueries", moSpatialQueries, null, DateTime.MaxValue, tsDelay, CacheItemPriority.Default, null);
                }

                if (oSemanticQueries == null)
                {
                    oSemanticQueries = new SemanticQueries();
                }
                
                strPerformanceLogFile = AppDomain.CurrentDomain.BaseDirectory + "\\queriesperformance.log" ;

               if (!File.Exists(strPerformanceLogFile))
                {
                    File.Create(strPerformanceLogFile).Close();
                }
            }

            catch (Exception exc)
            {
                throw (exc);
            }
        }

    }
}
